package com.mrx.commons.aop;

import ch.qos.logback.core.hook.ShutdownHook;
import com.mrx.commons.exception.BusinessException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.hibernate.validator.HibernateValidator;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author Mr.X
 * @since 2023-02-12 16:10
 */
@Aspect
@Component
public class AOPValidator {

    private final ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
            .configure().failFast(true).buildValidatorFactory();

    private final Validator validator = validatorFactory.getValidator();

    @Pointcut("@within(org.springframework.validation.annotation.Validated)")
    public void validator() {
    }

    @Before("validator()")
    public void before(JoinPoint joinPoint) {
        for (Object arg : joinPoint.getArgs()) {
            Set<ConstraintViolation<Object>> validateResult = validator.validate(arg);
            if (validateResult.size() > 0) {
                String res = validateResult.stream().map(ConstraintViolation::getMessage).collect(Collectors.joining());
                throw new BusinessException(res);
            }
        }
    }

    @EventListener(ShutdownHook.class)
    public void close() {
        validatorFactory.close();
    }

}
